#include "Sockets.h"
#include "planificador.h"
#define SOCK_PATH "echo_socket"
/*
 * Libería que permite realizar el manejo de sockets.
 * Nos focalizaremos en los de tipo UNIX, los más utilizados en la aplicación
 *
 */

int crearConexionConSocket(int puertoFSSyDisco, int* ficheroServer,
		struct sockaddr_in* server) {

	if ((*ficheroServer = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
		printf("No se pudo obtener el fichero descriptor del socket.\n");
		exit(-1);
	}
	printf("Se obtuvo el fichero descriptor correctamente.\n");

	(*server).sin_family = AF_INET;
	(*server).sin_addr.s_addr = INADDR_ANY; /* INADDR_ANY coloca nuestra direccion IP automaticamente */
	(*server).sin_port = htons(puertoFSSyDisco); /* htons transforma el short de maquina a short de red */
  bzero(&((*server).sin_zero), 8); /* Escribimos ceros en el resto de la estructura*/

	if (bind(*ficheroServer, (const struct sockaddr *) &(*server),
			sizeof(struct sockaddr)) == -1) {
		printf("Error al asociar el puerto al socket.\n");
		exit(-1);
	}
	printf("Se asocio bien el puerto al socket.\n");

	if (listen(*ficheroServer, BACKLOG) == -1) {
		printf("No se pudo dejar escuchando al puerto.\n");
		exit(-1);
	}
	return 1;
}


int conectar(int *iDescriptor_del_socket, char * sIP_remoto, int iPuerto_remoto_para_el_socket) {
	struct sockaddr_in structura_sockaddr;/*estructura para el Connect*/
	char sIP[16] = "\0";
   
  if (((*iDescriptor_del_socket)=socket(AF_INET, SOCK_STREAM, 0))==-1){
  printf("Socket() error\n");
  exit(-1);
  }
  
	sprintf(sIP, sIP_remoto);
	structura_sockaddr.sin_family = AF_INET;
	structura_sockaddr.sin_addr.s_addr = inet_addr(sIP);
	structura_sockaddr.sin_port = htons(iPuerto_remoto_para_el_socket);
	bzero(&(structura_sockaddr.sin_zero), 8);


	if (connect((*iDescriptor_del_socket), (struct sockaddr *) &structura_sockaddr,
			sizeof(struct sockaddr)) == -1)/*conect & check*/
	{
		perror("connect");
		return 0;
	}

	return 1;
}


int socketUnix_conectar(int iDescriptor_del_socket, struct sockaddr_un socket_un_struct,int len) {
	socket_un_struct.sun_family = AF_UNIX;
	strcpy(socket_un_struct.sun_path, stConfig.cPathSocketUnix);
	len = strlen(socket_un_struct.sun_path) + sizeof(socket_un_struct.sun_family);
	if (connect(iDescriptor_del_socket, (struct sockaddr *)&socket_un_struct, len) == -1) {
		perror("connect");
		exit(1);
	}
	return 1;
}

/*
 * Descripcion: Funcion que se encarga de crear el socket y asocia el mismo a una
 *
 */

/** Funcion que se encarga de crear el socket  AF_UNIX* */
int socketUnix_preparar(void) {
	int resultadoDePrepararSocket;
	resultadoDePrepararSocket=socket(AF_UNIX, SOCK_STREAM, 0);
	if ((resultadoDePrepararSocket) == -1) {
		perror("socket");
		exit(1);
	}
	return resultadoDePrepararSocket;
}

/** Funcion que se encarga de crear el socket  AF_INET* */

int prepararSocketInet(char * NOMBRE_PROCESO) {
	int resultadoDePrepararSocket;
	resultadoDePrepararSocket=socket(AF_INET, SOCK_STREAM, 0);
	if ((resultadoDePrepararSocket) == -1) {
		perror("socket");
		exit(1);
		}

return resultadoDePrepararSocket;
}

/**Funcion que setea al socket en estado de escucha a la espera de conexiones**/

int socketUnix_escuchar(int listener, int CantMaxClientes) {
	if (listen(listener, CantMaxClientes) == -1) {
		return 0;
	}
	return 1;
}

/** Funcion que se encarga del cierre del socket**/
int socket_cerrar(int iDescriptor_del_socket) {
	char sDescriptor_del_socket[16] = "\0";
	close(iDescriptor_del_socket);
	sprintf(sDescriptor_del_socket, "%i cerrado", iDescriptor_del_socket);
	return 1;
}


/**Función para poner a la escucha un socket**/
int socketUnix_bindear(int iDescriptor_del_socket, struct sockaddr_un socket_un_struct,int len) {
	socket_un_struct.sun_family = AF_UNIX;
	strcpy(socket_un_struct.sun_path, stConfig.cPathSocketUnix);
	unlink(socket_un_struct.sun_path);
	len = strlen(socket_un_struct.sun_path)
				+ sizeof(socket_un_struct.sun_family);
	if (bind(iDescriptor_del_socket, (struct sockaddr *) &socket_un_struct, len)
				== -1) {
		return 0;
	}
	return 1;
}

int mensaje_enviar(int descriptorSocket, int hecho) {
	int valorEnviado;
	valorEnviado=send(descriptorSocket, cadenaDeMensajeRecibido, variableAuxiliar, 0);
	if ( valorEnviado< 0) {
		perror("send");
		hecho=1;
	}
	return valorEnviado;
}

int mensaje_recibir(int32_t descriptorSocket,int32_t hecho) {
	memset(cadenaDeMensajeRecibido,'\0',100);
	variableAuxiliar = recv(descriptorSocket, cadenaDeMensajeRecibido, 100, 0);
	cadenaDeMensajeRecibido[variableAuxiliar-1] = '\0';
	if (variableAuxiliar <= 0) {
		if (variableAuxiliar < 0) perror("es el recv man");
		hecho = 1;
	}
	return variableAuxiliar;
}

int conexionCliente_Aceptar (int descriptor)
{
	socklen_t longitud;
	struct sockaddr Cliente;
	int descriptorDevuelto;


	longitud = sizeof (Cliente);
	descriptorDevuelto = accept (descriptor, &Cliente, &longitud);
	if (descriptorDevuelto == -1)
		return -1;


	return descriptorDevuelto;
}

int32_t socketInetCliente_abrir (int32_t puerto) {
	struct sockaddr_in Direccion;
	struct servent *Puerto;
	struct hostent *Host;
	int32_t Descriptor;
	Direccion.sin_family = AF_INET;
	Direccion.sin_addr.s_addr =inet_addr(stConfig.cIpEscucha);
	//Direccion.sin_addr.s_addr = inet_addr("192.168.1.34");
	//Direccion.sin_addr.s_addr = ((struct in_addr *)(Host->h_addr))->s_addr;
	Direccion.sin_port =htons(puerto);
	//Direccion.sin_port = Puerto->s_port;
	Descriptor = socket (AF_INET, SOCK_STREAM, 0);
	if (Descriptor == -1)
			return -1;
	if (connect (
				Descriptor,
				(struct sockaddr *)&Direccion,
				sizeof (Direccion)) == -1) {
		return -1;
	}
	return Descriptor;
}
int32_t socketInetServidor_abrir (int32_t puerto)
{
	struct sockaddr_in Direccion;

	int32_t descriptor;


	descriptor = socket (AF_INET, SOCK_STREAM, 0);
	if (descriptor == -1)
	 	return -1;


	Direccion.sin_family = AF_INET;

	Direccion.sin_port =htons(puerto);
	Direccion.sin_addr.s_addr = inet_addr(stConfig.cIpEscucha);
	//Direccion.sin_addr.s_addr = inet_addr("192.168.0.11");

	if (bind (descriptor,(struct sockaddr *)&Direccion,sizeof (Direccion)) == -1){
		close (descriptor);
		return -1;
	}


	if (listen (descriptor, 1) == -1)
	{
		close (descriptor);
		return -1;
	}

	return descriptor;
}
